<?php

declare(strict_types=1);

namespace App\Common\Middleware;

use Core\HyperfUnit\Webscan;
use Hyperf\HttpServer\Contract\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Hyperf\HttpServer\Contract\ResponseInterface as HttpResponse;
use Psr\Log\LoggerInterface;
use Core\HyperfUnit\Ip;
use Zms\Exception\AppException;

/**
 * 应用处理中间件
 */
class SystemMiddleware implements MiddlewareInterface
{

    protected RequestInterface $request;

    protected HttpResponse $response;

    protected LoggerInterface $logger;

    public function __construct(RequestInterface $request, HttpResponse $response)
    {
        $this->request = $request;
        $this->response = $response;
        $this->logger = logger('http', 'http');
    }


    /**
     * @param ServerRequestInterface $request
     * @param RequestHandlerInterface $handler
     * @return ResponseInterface
     * @throws AppException
     * @author 竹林风@875384189 2021/2/26 17:04
     */
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        //是否对数据安全扫描
        $is_check_data = configure('system.is_check_data');
        if ($is_check_data === '1' || $is_check_data === 1) {
            $this->checWebdata();
        }


        $response = $handler->handle($request);

        //判断是否要写访问日志
        $is_access_log = configure('system.is_access_log');
        if ($is_access_log === '1' || $is_access_log === 1) {
            $this->writeAccessLog($response);
        }
        return $response;
    }


    /**
     * 写入访问日志
     * @param ResponseInterface $response
     * @return void
     */
    private function writeAccessLog(ResponseInterface $response): void
    {
        $log = $this->request->getMethod() . ' || ' . $response->getStatusCode() . ' || ' . Ip::getIp();
        $uri = $this->request->url();
        $query = $this->request->query();
        $log .= ' || ' . ($query ? ($uri . '?' . http_build_query($query)) : $uri);
        $agent = $this->request->getHeader('user-agent')[0] ?? '';
        if ($agent) {
            $log .= ' || ' . $agent;
        }
        $this->logger->info($log);
    }


    /**
     * 对数据安全扫描
     * @return void
     * @throws AppException
     */
    private function checWebdata(): void
    {
        $types = configure('system.check_data_types') ?: ['post', 'get', 'cookie'];
        $param = [
            'post' => $this->request->post(),
            'get' => $this->request->query(),
            'cookie' => $this->request->getCookieParams()
        ];
        $webscan = Webscan::instance();
        if (is_array($types) && count($types) > 0) {
            $webscan->setWebscanPost(in_array('post', $types));
            $webscan->setWebscanGet(in_array('get', $types));
            $webscan->setWebscanCookie(in_array('cookie', $types));
        }
        if ($webscan->check($param) === false) {
            throw new AppException('数据安全验证失败');
        }
    }
}